#ifndef _EXPORTOBJECT_H_
#define _EXPORTOBJECT_H_

const int MAX_BLENDWEIGHTS=4;
const int MAX_BONES=256;
const int MAX_GEOMVERTICES=65536;
const int MAX_TEXMAPS=4;

#include <vector>
#include <string>
#include "point3.h"
#include "color.h"
#include "matrix3.h"
#include "imtl.h"

using namespace std;

class INode;
class ISkin;
class Modifier;
INode* FindRoot( INode *N );
bool IsXRefObj (INode *node);
bool IsMesh (INode *node);
bool IsBone (INode *node);
bool HasObject (INode *node);
bool IsSkinMesh (INode *node);
ISkin *ValidSkinModifier (INode *node);
bool IsSkinModifier (INode *node, unsigned i);
Modifier *ModifierAtIndex (INode *node, unsigned i);
UINT ModifierCount( INode *N );

const float MIN_INFLUENCE = 0.005f;
const float NONZERO_THRESHOLD = 0.000001f;

class ExportVertex
{
public:
	int id;
    Point3 Vertex;
	void Write(ostream &stream);
};

class ExportColor
{
public:
	int id;
    Color Color;
	void Write(ostream &stream);
};

class ExportFace
{
public:
	int id;
    DWORD vertex[3];
	DWORD color[3];
    Point3 Normal;
    int OrigIndex; // Original index of face in face list -> for skinmesh export
    int SurfaceID; // Surface ID -> for optimization
	DWORD SmGroup;
	void Write(ostream &stream, bool cvert);
	void CleanUpData();
};

class ExportVertexWeight
{
public:
	class BoneInfluence
	{
	public:
		BoneInfluence()
		{
			Weight = 0;
		}
		float Weight;
		string BoneName;
	};
	vector<BoneInfluence> Weights;
};

////////////////////////////////////////////////////////////////////////////////////////////////
// ExportMaterial
////////////////////////////////////////////////////////////////////////////////////////////////
class ExportMaterial
{
public:
    ExportMaterial()
    {
    }
	string Name;
    string m_szTextureName[MAX_TEXMAPS];
    string m_szBumpName;
    float Opacity, SpecularLevel;
    bool bTwoSided, bSpecular, bEnvironment;
    Color Ambient, Diffuse, Specular;
    void FillData( Mtl *Material );
    void Write(ostream &stream);
};

class ExportSurface
{
public:
    ExportSurface() {  }
    ~ExportSurface() {}
    ExportMaterial *Material; // Don't delete, not owned
    vector<int> Faces;
    int StartFace, FaceCount;
};

////////////////////////////////////////////////////////////////////////////////////////////////
// ExportObject
////////////////////////////////////////////////////////////////////////////////////////////////
class ExportObject
{
public:
    // properties
    Matrix3 Transformation;
    string Name;
    ExportObject *Parent;
    vector<ExportObject*> Children;

    bool bNoParent; // Don't transform back into parent's coord system
    bool bNoChildren; // Has no children

    ExportObject() : Parent(0)
	{
    }
    virtual ~ExportObject() {  }
    virtual void BeginWrite( ostream &stream )=0;
	virtual void EndWrite( ostream &stream )=0;
    static ExportObject* BuildFromINode( INode *N, bool bNoParent = false );
    virtual void FillData( INode *N );
    void CreateHierarchyList( vector<string> &list ); // Creates a list of mesh names in hierarchy (in-order visit)
protected:
	string Type;
};

////////////////////////////////////////////////////////////////////////////////////////////////
// CEmptyObject
////////////////////////////////////////////////////////////////////////////////////////////////
class cFile;
class CEmptyObject : public ExportObject
{
public:
    CEmptyObject() : ExportObject() {};
    virtual void FillData( INode *N );
	virtual void BeginWrite( ostream &stream ) {};
	virtual void EndWrite( ostream &stream ) {};
};

////////////////////////////////////////////////////////////////////////////////////////////////
// CExportMesh
////////////////////////////////////////////////////////////////////////////////////////////////
class CExportMesh : public ExportObject
{
public:
	int NumVertices;
	int NumCVertices;
    int NumFaces;
    int NumVertAnimPhases;
	bool HasVertexColors;
    string AnimName;

    ExportVertex *Vertices;
	ExportColor *Colors;
    ExportFace* Faces;

    int NumSurfaces;
    int NumUsedSurfaces; // Surfaces which are really used (NumFaces>0)
	int m_iUVChannels;
    ExportSurface *Surfaces;

	CExportMesh(): ExportObject(), HasVertexColors(false), m_iUVChannels(1), NumVertAnimPhases(1), Vertices(0), Colors(0), Faces(0), Surfaces(0), NumVertices(0), NumFaces(0), NumCVertices(0)
    {
		Type="MESH";		
    }
	~CExportMesh();
	void WriteSurface(ostream &stream, ExportSurface &surf);
    virtual void BeginWrite( ostream &stream );
	virtual void EndWrite( ostream &stream );
    virtual void FillData( INode *N );
};

////////////////////////////////////////////////////////////////////////////////////////////////
// CExportWeightMesh
////////////////////////////////////////////////////////////////////////////////////////////////
class CExportWeightMesh : public CExportMesh
{
public:
	CExportWeightMesh() : CExportMesh()
	{
		Type = "SKINMESH";
		Weights = 0;
		bNoChildren = true;
    }
    ~CExportWeightMesh();

    virtual void FillData( INode *N );
    virtual void BeginWrite( ostream &stream );
	virtual void EndWrite( ostream &stream );

    void CorrectBoneIndices(); // Corrects bone indices to my structure (identifies the bones by their names)

    ExportVertexWeight* Weights;

};

#endif
